package com.google.code.gronono.gps.ui.panels.pages.tree;

import javax.swing.JTree;
import javax.swing.event.TreeSelectionEvent;
import javax.swing.event.TreeSelectionListener;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.TreePath;
import javax.swing.tree.TreeSelectionModel;

import com.google.code.gronono.gps.model.SortedFile;

/**
 * Listener de sélection sur les arbres utilisés dans l'application.
 * <br/>Implémente notamment la sélection réciproque dans l'arbre 'opposé' du noeud correspondant au noeud sélectionné.
 */
public class SortedFileTreeSelectionListener implements TreeSelectionListener {
	/** L'arbre source. */
	private final JTree srcTree;
	/** L'arbre cible. */
	private final JTree dstTree;

	/**
	 * Constructeur.
	 * @param srcTree L'arbre source.
	 * @param dstTree L'arbre cible.
	 */
	public SortedFileTreeSelectionListener(final JTree srcTree, final JTree dstTree) {
		this.srcTree = srcTree;
		this.dstTree = dstTree;
	}

	/* (non-Javadoc)
	 * @see javax.swing.event.TreeSelectionListener#valueChanged(javax.swing.event.TreeSelectionEvent)
	 */
	public void valueChanged(final TreeSelectionEvent e) {
		final TreeSelectionModel sourceModel = (TreeSelectionModel) e.getSource();

		TreeSelectionModel destinationModel = srcTree.getSelectionModel();
		JTree destinationTree = srcTree;
		if (sourceModel.equals(srcTree.getSelectionModel())) {
			destinationModel = dstTree.getSelectionModel();
			destinationTree = dstTree;
		}

		// On cherche à sélectionner le noeud de l'arbre 'opposé' correspondant au noeud sélectionné
		for (final TreePath path : e.getPaths()) {
			final DefaultMutableTreeNode selectedNode = (DefaultMutableTreeNode) path.getLastPathComponent();
			final SortedFile sortedFile = (SortedFile) selectedNode.getUserObject();
			if (sortedFile.getDstFile() != null) {
				final DefaultMutableTreeNode dstNode = findInTree((DefaultMutableTreeNode) destinationTree.getModel().getRoot(), sortedFile);
				if (dstNode != null) {
					final TreePath dstPath = new TreePath(dstNode.getPath());
					if (e.isAddedPath(path)) {
						destinationModel.addSelectionPath(dstPath);
						destinationTree.scrollPathToVisible(dstPath);
					} else {
						destinationModel.removeSelectionPath(dstPath);
					}
				}
			}
		}
	}

	/**
	 * Méthode permettant de retrouver un noeud dans un arbre.
	 *
	 * @param rootNode Le noeud racine.
	 * @param sortedFile le sortedFile qu'on recherche.
	 * @return Le noeud correspondant au sortedFile, <code>null</code> si pas trouvé.
	 */
	private DefaultMutableTreeNode findInTree(final DefaultMutableTreeNode rootNode, final SortedFile sortedFile) {
		DefaultMutableTreeNode result = null;
		for (int i = 0; i < rootNode.getChildCount(); i++) {
			DefaultMutableTreeNode node = (DefaultMutableTreeNode) rootNode.getChildAt(i);
			if (node.getUserObject().equals(sortedFile)) {
				result = node;
				break;
			}
			node = findInTree(node, sortedFile);
			if (node != null) {
				result = node;
				break;
			}
		}
		return result;
	}

}
